package com.nowcoder.community.service;

import com.nowcoder.community.contant.Entity;
import com.nowcoder.community.utils.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class FollowService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    // 关注/取关
    public int follow(int userId, int entityType, int entityId){
        String followingRedisKey = RedisKeyUtil.getFollowingRedisKey(userId, entityType);
        String followerRedisKey = RedisKeyUtil.getFollowerRedisKey(entityType, entityId);

        Double followTimeStamp = redisTemplate.opsForZSet().score(followingRedisKey, entityId);
        if (followTimeStamp == null){
            // 进行关注
            // 向 用户的 following 添加 实体id
            // 向 实体的 follower 添加 用户id
            redisTemplate.execute(new SessionCallback() {
                @Override
                public Object execute(RedisOperations operations) throws DataAccessException {
                    redisTemplate.multi();;
                    redisTemplate.opsForZSet().add(followingRedisKey, entityId, System.currentTimeMillis());
                    redisTemplate.opsForZSet().add(followerRedisKey, userId, System.currentTimeMillis());
                    return redisTemplate.exec();
                }
            });
            return 1;
        }else {
            // 取消关注
            // 向 用户的following 删除 实体id
            // 向 实体的follower 删除 用户id
            redisTemplate.execute(new SessionCallback() {
                @Override
                public Object execute(RedisOperations operations) throws DataAccessException {
                    redisTemplate.multi();;
                    redisTemplate.opsForZSet().remove(followingRedisKey, entityId);
                    redisTemplate.opsForZSet().remove(followerRedisKey, userId);
                    return redisTemplate.exec();
                }
            });
            return 2;
        }
    }

    // 用户是否关注某个实体
    // 实体id 是否存在 用户的following 中
    public boolean hasFollowed(int userId, int entityType, int entityId){
        String followingRedisKey = RedisKeyUtil.getFollowingRedisKey(userId, entityType);
        return redisTemplate.opsForZSet().score(followingRedisKey, entityId) != null;
    }

    // 统计用户关注某类实体的数量
    public int countFollowing(int userId, int entityType){
        String followingRedisKey = RedisKeyUtil.getFollowingRedisKey(userId, entityType);
        Long count = redisTemplate.opsForZSet().zCard(followingRedisKey);
        return count == null ? 0 : count.intValue();
    }

    // 统计实体的粉丝数量
    public int countFollower(int entityType, int entityId){
        String followerRedisKey = RedisKeyUtil.getFollowerRedisKey(entityType, entityId);
        Long count = redisTemplate.opsForZSet().zCard(followerRedisKey);
        return count == null ? 0 : count.intValue();
    }


    // 获取粉丝列表
    public List<Map<String, Object>> findFollowers(int userId, int offset, int limit){
        String followerRedisKey = RedisKeyUtil.getFollowerRedisKey(Entity.USER, userId);
        return getUserList(followerRedisKey, offset, limit);
    }

    // 获取关注用户列表
    public List<Map<String, Object>> findFollowings(int userId, int offset, int limit){
        String followingRedisKey = RedisKeyUtil.getFollowingRedisKey(userId, Entity.USER);
        return getUserList(followingRedisKey, offset, limit);
    }


    private List<Map<String, Object>> getUserList(String redisKey, int offset, int limit){
        Set<Integer> uids = redisTemplate.opsForZSet().reverseRange(redisKey, offset, offset + limit - 1);
        List<Map<String, Object>> list = new LinkedList<>();
        if (!uids.isEmpty()) {
            for (Integer uid : uids) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("user", userService.findUserById(uid));
                map.put("followTime", new Date(redisTemplate.opsForZSet().score(redisKey, uid).longValue()));
                list.add(map);
            }
        }
        return list;
    }
}
